查看原文
其他

阿里P9专家右军:以终为始的架构设计

右军 中生代技术 2021-08-09
P

右军

读完需要

17分钟

速读仅需 6 分钟

右军(于君泽),蚂蚁金服P9技术专家,在 IT 领域从业超过十五年。对 高并发、分布式架构、内建质量、研发管理有一些心得。维护公众号“技术琐话”,合著有《深入分布式缓存》、《架构宝典》、《程序员的三门课》等书籍。本文摘取自《架构宝典》


1


   

缘起


世界上有两件东西能震撼人们的心灵: 一件是我们心中崇高的道德标准,另一件是我们头顶上灿烂的星空。——康德

架构是一种思维模式,可以理解为系统化地看待周遭事物并提出解决方案。从这个角度讲,小到一段代码,中到一个模块,大到一系列产品集都有其架构层次。我们常常听到 的抽象、扩展、复用、分层都是常见的架构设计手段。一位程序员经常做架构思维的训练 和实践,然后成长为一位系统或者平台架构师,这是一种自然演化的成长路径。所以说, 架构思维非架构师独有,架构师也非天降神人,而是通过实践、学习成长而来的。

架构师是连接商业世界与技术世界的桥梁,如同金门大桥一样(如图 2.1 所示),《软件架构师的 12 项修炼: 技术技能篇》一书曾大篇幅论述接触客户的重要性,通过调研、会 谈、引导等方式了解你的客户,了解产品展开竞争的市场,从而研究业务目标,考虑能为 客户做什么,在尘土飞扬的商业背面来设计 IT 系统。比如,客户告诉你的未必是真正的需求,而是要挖掘背后的本质需求。此时,往往需要考虑如下几个要点:

  • 他们的“痛点”是什么?

  • 如何让他们更高效地工作?

  • 你如何满足他们的需求?

因此,架构师不仅仅要懂得技术选型、约束,有丰富的代码研发经验,对于非功能性需求(比如性能、事务设计)有丰富的应对策略,还需要足够了解业务,了解客户需要什 么,并知道如何衡量产品是否成功。这种成功是真实的成功,而不是象牙塔和实验室中架构师们假想的那种成功。

图 2.1

笔者主张的架构设计思想,一言以蔽之就是以终为始。只有从需求出发,才能衡量架构设计的成败,也才能不偏不倚地不断评估当下所走之路是已经偏离了路线还是已经迷路 了。

2


   

我们的思考方式

在抛出笔者的观点之前,先来看一下黄金圈理论,该理论由著名的营销顾问西蒙·斯涅克提出,如图 2.2 所示。

一般的营销方式是“这台电脑功能强大,性能优秀,买一台吧”! 但苹果这样的公司恰恰相反,苹果公司的营销方式实际上是这样的: “我们做的每一件事情,都是为了突破和创 新。我们坚信应该以不同的方式思考。我们挑战现状的方式是把我们的产品设计得十分精 美,使用简单,界面友好。我们只是在这个过程中做出了最棒的电脑。想买一台吗?”

在制定营销策略时,运用此黄金圈,从 why 开始,再到 how,最后再考虑 what。即先找到“为什么”,建立自己的核心价值理念,突出“为什么”,个性鲜明、追求极致,并始终用 why 来检验 how 与 what!接下来,尝试用 why-how-what 的思路来分别谈一下我对软件架构的一些想法。

图 2.2


3


   

为什么要做架构设计

3.1


   

由模型到实施

无数的著作都论及软件架构和建筑的关系。我认为架构就如同一张蓝图,没有图纸很难建造房屋。如图 2.3 所示,一个令人神往的海边建筑涉及的方方面面非常多,具体实施过程还包括各种测量和计算,没有一个架构设计过程是不可能的。

图 2.3


图 2.4

图 2.4 所示,室内的图纸也有建筑分布、水电图等,以服务于不同的目标。水电图指导水电施工,如果搞错了,再返工也是蛮复杂的一件事情。

3.2


   

业务规模发展带来的复杂度

如果说设计师给你的效果图相当于 UI 设计的话,那么建筑工人建造的就是设计的骨架了(比如架构分层、部署)。而合适的架构可以见微知著,适应变化,在快速规模化效应到来时较好地解决客户问题,如图 2.5 和图 2.6 所示的 2 个例子。

图 2.5

图 2.6

一艘民用的船只如果发展成一艘巨舰,在安全性、载重、动力设备、船只内部设计等各方面都有差异。而对于时下很火热的线下 O2O 业务,广大群众乐于比较价格,计算各种优惠,厂商也乐此不疲地发展营销创新,从街头的跳楼价到打折,不一而足。如图 2.6 所示的例子,起初的优惠方式为:打折、立减。转换为规则的表达就是 X*折扣比例及 X−Y(折扣金额)。演变到第二阶段时,优惠方式增加了累计,就是打折和立减同时生效。演变到第三阶段便出现了有条件的累计优惠,阶梯性优惠,指定品种/数量优惠等情况。从三个阶段的可扩展性层面来设计优惠规则,其实并不简单,因为后期的需求与起初相比已经有很大的不同。

3.3


   

从沟通视角看软件架构

在 Simon Brown 所著的《程序员必读之软件架构》一书中,提到了软件架构的若干好 处,其中有不少是从沟通视角来看的,如下。

  • 让技术团队跟随一个清晰的愿景和路线图。

  • 对不同的听众,以不同层次的抽象来交流相应的问题域和解决方案。

对于第二点,笔者感同身受。有时候,当产品经理、应用架构师、开发人员甚至还有业务领域专家一起讨论交流时,大家对一个概念有不同的说法,统一名称、形成共识往往 是设计架构方案的第一步。

4


   

如何做架构设计

对于如何做架构设计,笔者总结了以下几点。

  • 以终为始,不忘初心。

  • 使用 PMC(Production Material Control,生产及物料控制)框架。

  • 聚焦 SLA(Service-Level Agreement,服务等级协议)。

  • 满足利益相关者的需要。

  • 从多视角、多层次看架构。

  • 全息视图分析。

  • 抽象、协作、扩展、复用。前 4 点本质上都是从客户价值出发的,第 5 点和第 6 点针对的是多层次视图问题,第 7 点谈的是探寻架构的基本方法。下面和大家具体谈一谈。

4.1


   

以终为始,不忘初心

笔者在如何做架构设计这部分旗帜鲜明地提出: 以终为始,不忘初心。初心是什么, 就是用户的本质需求。如图 2.7 所示,不论系统如何组织,用户最关心的是响应时间 (Response Time,RT),以及展示的金额是否准确。所以,在一开始设计时就要考虑如何获 取到用户关注的两个要素——体验和准确性。是否要考虑链路级的监控,以及链路级的关 键数据校验;如果规则分散到多个系统,如何检查整体组合的命中等情况;链路上每个系统的容量和响应时间是多少;等等。以上这些都在考虑之列。

图 2.7


4.2


   

PMC 框架

什么是 PMC 框架呢?P 代指平台侧(Platform),M 代指商户侧(Merchant),而 C 代指用户侧(Customer)。平台型的产品都有这三端的考量。在构建一个具体软件的时候,一 定要搞明白它在服务谁? 是用户还是商户,还是兼而有之。以天猫、Uber 和某 O2O 的 App 来进行比较,如图 2.8 所示,其中 C 端为客户端,B 端为商户端。滴滴或 Uber 解决出行的问题,电商解决网上购买商品的问题。平台设计的本质是符合平台侧、商户侧、用户侧的三端诉求。比如,电商的 IM 解决信息沟通问题,客服解决售后,还有其他方式解决可能的作弊、交易、安全及评价体系等一系列的问题。Uber 也是基于交易的平台,乘客需要付款给司机,用户的需求则是更快更省地叫到车,司机的信用评价沿用了星级评价、投诉等保障措施,但对于 Uber 来说,基于地理位置的撮合(用户的地点,以及在一定范围内寻找可以承载他的车,包括允许共享座位的车)是其核心,也是 Uber 孵化出 dispatch 模块的原因。

图 2.8

有意思的事情发生了,Uber 老板一觉醒来发现他创造的不仅仅是一家出行公司,如图 2.9 所示。司机和车只是平台的资源,供应方(Supply)可以是一家蛋糕店、鲜花店或者是西湖 的休闲船只管理中心,那么面向不同的供应方,该平台架构的哪些能力是可以复用的呢? 如下:

  • 调度能力。

  • 用户呼叫的界面、策略(大部分)。

  • 地理位置处理。

  • 交易事后处理等。

图 2.9

大部分变化在于运送的物品(属性)及一些附属需求,而这些都是可以通过良好的平台设计及可扩展的新市场产品特性来完成的。有一位互联网圈资深产品经理曾提及要识别刚需和伪需求。刚需比如衣食住行,而我理解的伪需求或许是小众需求,只针对特定客户体现其价值,并可能仅仅是一点点演绎, 而非本质需求。做软件架构设计,识别本质需求比较重要。比如客户让你把对账单导出成 Excel,可能他还需要导入手工账单,以便和自己记账的数据做核对,那么如何提供对账功能给用户就值得再考虑了。

4.3


   

架构非单一视角、单一层次

由于不同角色对领域或者概念的理解存在差异,因此很容易导致频繁的争吵不休。前面提到了统一概念定义,讨论了远景、目标和价值,但是在更具体的讨论中,往往有可能陷入第二个层次的喋喋不休,研发管理者往往乐见这些争吵。模拟一下管理者的心理:

“嗨,比尔,你看,架构师讨论得多专注,多投入啊! 一个概念问题竟然讨论了大半天, 对自己要求太严格了!这是工匠精神呢!”

另外一个场景就是,小 V 在说红包是一个支付工具,而小 B 说它明明是一个营销工具。有时候还上升到哲学层面,比如门是因为有把手才成为门,还是因为它本来是门,把手是它的组成部分。笔者也乐见架构师们不断探究的精神,但是有以下两点建议:

  • 应该给争论设置一个时间节点——由于有些概念未明晰,工作便无法开展,因此争论有时不可避免;而有些概念并不影响现阶段甚至下一步工作的开展,因此需要避免对这些概念的过度争论。不要忘了,争论是为了更好地构建软件系统,而软件是为业务服务的。

  • 争论的问题未必是“非黑即白”的选择题,事物往往具有复杂性,通过不同维度和层次的抽离,可以看见不同层次的本源。比如 CTG-MBOSS 功能架构就对电信业务领域做了客户产品、服务、资源、企业管理的划分,又基于提供、保障、计费这个 层次做了划分,如图 2.10 所示。

有同学可能会问,多个视角有什么用呢?图 2.10 从颜色区分了业务支撑、运营支撑、 企业管理等。不难理解,业务支撑直接面向用户前端,而运营支撑是支持业务支撑的,比如产品管理、网络资源管理。运营支撑能力直接影响到前端业务的效率、体验和 SLA。以一个第三方支付的应用为例。单就这样一个应用来说就有诸多的考量因素,比如风控、营销、签约(签约的顺畅度)等,如图 2.11 所示。

图 2.10

图 2.11

图 2.11 提及的维度已经很全面了,但毕竟是离散的,可以进一步进行分类管理,分类如下。

  • C 端业务主路径: 支付。

  • B 端业务路径:签约、收单、核对。

  • 平台端业务:签约流程管理(商户、产品、接口、费率、优惠等),收单流程管理(收单、支付、风控、额度、渠道、优惠)。

根据企业运营业务的经验,可以抽象出一种典型的组织形式: 业务执行、业务运营、企业内部运营和主数据,如图 2.12 所示。业务执行、业务运营等视角又可以加以组合,组合可以用来考量设计的要素(谁为谁服务)。比如营销是业务运营的板块,是为了更好地执行业务。Uber 的打折优惠也好,免费拼车也好,都是不影响主流程的,是可以进一步刺激消费的设计; 然而,有的产品把营销活动设计得极其生硬,极其难用,相当于把一件大人的衣服穿到了一个小朋友身上。或许可以有这样一种设计,可以对产品的流量进行分析,当检测到某项指标达到某一阈值时,便强烈预警产品应该优化,并能通过分析给出优化建议。可能一开始数据不够准确,但是通过不断训练和尝试,可以形成正循环。

百度的朋友曾经在某个会议上分享过通过快速构建 MVP 以及收集舆情信息,不断优化产品迭代的案例,这就是一种蛮有意思的尝试,业务运营一定要为业务执行(产品)服务。

图 2.12

4.4


   

满足利益相关者的需要

在写本部分内容时,我的好友同时也是时任诺基亚创意经理、架构师的石涛声向我推荐了《软件系统架构:使用视点和视角与利益相关者合作》一书,说我的某些观点与此书有相通之处。什么是利益相关者?利益相关者最终会对软件产品或者系统的范围、功能、 操作特性和结果做出决定并产生影响。没有利益相关者就没有必要创建架构,因为没有人来构建部署它或者为此付费。

好的架构描述能够向利益相关者对架构的关键内容进行有效的展示。

4.5


   

聚焦 SLA

SLA 的全称是 Service-Level Agreement,意思是服务等级协议。聚焦 SLA,有如下两 个明确的注意事项。

  • 避免关注枝节遗忘全局。

  • 避免关注自身忘却出发点。

前面阐述了从客户价值出发构建架构,同时考虑 C(客户侧)、P(平台侧)、M(商户侧)的不同诉求。那么如何衡量这些诉求是否实现了呢?答案是需要清晰明确地设定 SLA。

举个例子,12306 这个众所周知的火车票购买网站由于经历了 2012 年的阻塞、间或的宕机及与黄牛(抢票软件等)斗智斗勇开启了“杀伤力巨大”的图片校验码而引发众多吐槽。那么,12306 给客户带来的价值是什么呢? 首先是让尽量多的人买到票(票的数量受制于运输能力),另外是让人能够比较顺畅地买到票,再者是公平性(开发抢票软件的浏览器是不是应该治理,还有那些倒卖的地下软件)。有专家说 12306 不应该把图片校验码弄得这么复杂,对抗黄牛不是主要依靠这种手段。我认为只说对了一半,防作弊的确是它要做的事情,这是为了客户价值而做的。但是,有报道称,对 12306 图片识别困难的回应是能买到票就不错了。这样的说法显然降低了对价值实现的认可。另外,虽然票最终是会卖完的, 但是票以什么样的方式卖完,大部分人购买时是否顺畅也是非常重要的(近些年已经没有出现宕机问题了)。说了这些,大家不妨梳理一下实现客户价值的方法,比如是否可以使用预约的方法, 只有预约才有资格买票,且实行 7×12 小时分批次购买等; 再比如运行程序时如何区分是普通用户还是刷票软件,针对不同的渠道采取不同的策略,这里肯定有不少事情可以做, 而不是一图难天下。

讲了 12306,再来看一个例子。以图 2.13 所示的第三方支付为例(仅作示意,切莫细究图示模块内容的完备性)。业务运行(支付业务)涉及用户下单、形成交易并支付等相关处理,而用户非常关注能不能快速、正确且安全地进行支付。为了求证付款正确性,他们也会习惯性地在第一时间查询消费记录。对于商户而言,他们也有查询收支明细的诉求。到这里,可能有人会问,了解 SLA 要求和具体的架构设计存在哪些关联呢?

图 2.13

图中的空白方框代表不方便公开的隐藏业务。

仍以图 2.13 为例,可以用一系列假设做恰当的预设计,如图 2.14 所示。

图 2.14

比如从系统运行角度看,如何度量用户 SLA(体验顺畅度、支付成功率、从下单到完成支付花费的时间)以及更多行为数据(用户在哪一步流失的,什么原因)等。要做这些,就需要全链路的监控,进而需要做统一的上下文、事件码来串联请求的链路(traceId 描述 技术语义,业务语义则可能被 userId 所描述)。再举一个例子,在数据量 100 万级的情况下, 可能以 buyerId 或者 sellerId 为查询条件分别满足按买家、商家不同维度的消费记录查询。当数据规模扩大之后,可以通过数据库表的拆分来做 Sharding,此时,则涉及键(key)的选取问题,该问题就是比较典型的多维度查询问题。

4.6


   

抽象、协作、扩展、复用

抽象、扩展人人都知道,但是如何识别本质而不做 BDUF(Big Design Up Front)则并不容易。以 Uber 为例,Uber 的定位已经不仅仅是一家出行公司,而是一家可以利用其物流能力叫飞机、叫外卖,包括送花的公司,如图 2.15 所示。要知道 Uber 也不是一天炼成的。有文章披露,旧系统是为专用客车运输所设计的,其中做了很多假设:每辆车一个乘客,不适用 Uber Pool(拼车服务)。将运送人的想法深深嵌入数据模型和接口里,会限制将该架构扩展到新的市场和产品上,比如运送食物和箱子。最初的版本是按城市来划分的。这样做对于可扩展性而言是好的,每个城市可以独自运营。但当越来越多的城市加入的时候,这就变得越来越难以管理。城市有大有小,负载也不一样。后来,他们重构了 dispatch 模块,让调度的接口不依赖具体的专用客车领域而具备可扩展性,并通过微服务来做切分和管理。

图 2.15

4.7


   

全息视图分析

笔者有一个观点,就是要从全局视图来看问题,拘泥于细节上的问题会出现“一叶障目不见泰山”的情况。在软件的设计模式里有一个拦截器模式,在软件思想里有面向切面的设计,比如著名开源软件 Spring 的 AOP 思想。面向切面也是架构设计的一个分析思路, 比如可以分析稳定性及性能,包括对应系统特有的资金安全等。如图 2.16 所示,一个支付系统外部连接商户系统,中间做支付处理,后台与银行或其他支付机构进行通信。那么在幂等性、接口的结果状态和错误码约定方面都要做相应的处理。

图 2.16

仅以网关系统和银行机构的通信做一下说明,因为如果二者的约定出了问题,则后果不堪设想。比如银行返回未知或处理中,而如果支付系统当成支付失败来处理,则最终银行处理成功时可能会导致用户资产损失。

5


   

架构是什么

最后,笔者抛出 3 个观点来谈谈架构是什么的问题。回顾一下前辈们对“架构是什么”的看法,架构有组成派和决策派两派观点,而我的 观点是: 架构兼具组成和决策的特点,架构之于架构是自包含关系。

5.1


   

架构兼具组成和决策的特点

Mary Shaw 在《软件体系结构:一门初露端倪学科的展望》一书中论及软件系统的架 构时,将系统描述为组件及组件之间的交互。而“Rational 统一过程”则重点表达了以下观 点。软件架构包含了关于以下问题的重要决策:

  • 如何对软件系统进行组织。

  • 如何选择组成系统的结构元素和它们之间的接口,以及如何设计当这些元素相互协作时所体现的行为。

  • 如何组合这些元素,使它们逐渐合成更大的子系统。

  • 如何让用户知道这个系统组织的架构风格:这些元素及它们的接口、协作和组合。

软件架构并不仅仅注重软件本身的结构和行为,还注重其他特性:使用、功能性、性能、弹性、重用、可理解性、经济和技术的限制与权衡,以及美学。

5.2


   

架构是演进来的

架构是演进来的,是动态的。业界关于架构是预先设计出来的还是演进出来的颇有些争论(《恰如其分的软件架构》一书就提及了计划式设计、演进式设计等观点),笔者的观点是比较明确的,不倒向任何一方,而是认为:

  • 软件架构需要做事先设计,而演进式架构号称是采用 TDD、重构、持续集成等手段 保障其演进的。但敏捷实践里面的 TDD 是从微观视角来看的,重构也可以以微观 视角进行。宏观视角需要对整体架构进行设计,让参与者具有共同的愿景,并做出共同的决策。比如,技术框架如何选型、怎样评估用户并发、用户是谁,以及如何提供服务等。

  • 不做 BDUF,暂缓做不确定的事,不做大投入的方案。任何一个选择都需要考虑投资回报率(ROI)。

  • 架构处于一个动态的过程中,是不断演进的。除了微观的重构及敏捷实践会演进, 领域模型和架构方案亦可持续演进。

  • 偿还技术债务、重构和不断抽象、分解问题域是演进的一些手段,保持架构演进要特别持续关注质量并保障其没有下降。

图 2.17 是一个大公司架构生命周期的活动图。从架构规划到架构实施,其中有不断的架构沟通。而架构实施的反馈又将纳入下一代的架构规划中。下一代架构规划,一方面要纳入现阶段的问题,另一方面要基于行业领域知识、同行参考和商业洞察进行。2011 年,我们做过一个不太成功的示范,在产品层之下设计了一个基础层,做核心领域的沉淀,后来孵化出了 10 多个小产品,结果核心的两张表被过度抽象,但这对于不确定性很强的业务是不合适的。完全烟囱模型+插件(或工具黏合剂)的方式可能更合适。

2.17

5.3


   

无纯粹的非功能特性

这一节其实想表达的是功能特性与非功能特性的区分不够好。什么叫非功能特性?有 人也称之为质量特性。笔者觉得一切都是质量,所以在商业需求呈现过程中一定要区分下 面两条需求的意义其实不大。

  • 登录三次,锁定账号 20 分钟。

  • 系统需要支持 2000 个用户同时并发。

另外一个区分功能特性与非功能特性的危害是容易把非功能特性当作增强性要素。增强性要素就是重要,但紧急程度不高,可以让用户先用起来的要素。

笔者的观点很明确,应该把所有需求放到一起排序,而基于安全性、高可用这些面向 切面的分类,只是为了更好地管理架构的各个组成部分而已。同时,在团队分工上也可以 术业有专攻。以图 2.18 为例,可以看到每个约束要求都对应具体可操作、可验证的功能, 比如数据安全性、通信安全性。

图 2.18

6


   

总结

综上所述,软件架构工作看似简单,其实不然。系统化思考有助于理清软件架构流程及从客户价值出发,识别用户、设定 SLA 可以帮助软件架构设计人员和研发人员避免在技术纷繁复杂的跋涉中迷失而陷入“自嗨”。架构是演进出来的,架构包含了一系列的决策和若干组成,架构应该从全局视角看问题。有人说,读完本章还是不知道该如何做。那就再帮帮你:

  • 对于新项目,请利益相关者进行分析,了解大家的需求;对于老平台,检查利益相关者的需要,规划后续发展方向。

  • 请度量产品对于用户、商户的 SLA(接入效率、接入成本、用户体验、稳定性、应急处理能力等),面向服务对象做规划和设计。

  • 适当的时候考虑链路级业务监控视图。

  • 在系统链路调用中加上 traceId 这样的标识。

  • 考虑平台沉淀能力时,要考虑业务形态的扩展,确定投入产出比再进行扩展。

  • 在不同阶段采用不同的架构,说不定在试水期的阶段烟囱型架构是最合适的,因为(业务上)短期的价值是突出产品核心功能,并不求全,先度过生存期是第一要务。

  • 非功能要素不是加分项,却可能是主体价值的体现,比如商户需要一个批量导入接口,你提供了单笔处理接口,这是严重的信息不对称导致的,批量导入接口看起来是为了提高处理性能,但是它其实也提高了业务处理的便利性,这也是功能特性的一部分。

  • 非功能要素依据重要程度也可能需要融入日常研发中,比如微软的同仁分享的 Office 的故事。Office 产品需要不断校验安装包大小,因为功能增加,变成巨无霸 可能会影响性能,所以就需要依据重要程度将这些非功能要素融入日常研发中。

想要加入中生代架构群的小伙伴,请添加群合伙人大白的微信

申请备注(姓名+公司+技术方向)才能通过哦!


   END     

#接力技术,链接价值#




精彩推荐

1. 从0到1设计一个秒杀系统
2. 苏宁金服技术大揭秘:支付决策机器人
3. 手哥架构宝典系列:支付系统1.0架构演进
4. 手哥架构宝典系列:支付系统2.0架构演进


漫画推荐


1. 漫画:程序员和产品经理撕得真是太太太太厉害了
2. 漫画:程序员真的是太太太太太太太太难了!
3. 漫画:普通程序员 vs 优秀程序员
4. 漫画:35岁的IT何去何从?
5. 漫画:从修灯泡来看各种 IT 岗位,你是哪一种?
6. 漫画:一批90后已经30岁了,更扎心的是…
7. 图解:这才是程序员加班的真正原因!
8. 漫画:中国互联网往事(2000-2020)

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存